import fs from "fs/promises";
import path from "path";

export class BackupManager {
  private backupDir: string;
  private maxBackups: number = 5;

  constructor(baseDir: string) {
    this.backupDir = path.join(baseDir, ".backups");
  }

  private async ensureBackupDir() {
    await fs.mkdir(this.backupDir, { recursive: true });
  }

  private getBackupPath(filePath: string, timestamp: number): string {
    const relativePath = path.relative(process.cwd(), filePath);
    const backupName = `${relativePath.replace(
      /[\\/]/g,
      "_"
    )}.${timestamp}.bak`;
    return path.join(this.backupDir, backupName);
  }

  private async getBackups(filePath: string): Promise<string[]> {
    await this.ensureBackupDir();
    const files = await fs.readdir(this.backupDir);
    const relativePath = path.relative(process.cwd(), filePath);
    const prefix = `${relativePath.replace(/[\\/]/g, "_")}.`;

    return files
      .filter((file) => file.startsWith(prefix) && file.endsWith(".bak"))
      .map((file) => path.join(this.backupDir, file))
      .sort((a, b) => {
        const timestampA = parseInt(a.split(".").slice(-2)[0]);
        const timestampB = parseInt(b.split(".").slice(-2)[0]);
        return timestampB - timestampA; // Sort newest first
      });
  }

  async createBackup(filePath: string): Promise<void> {
    await this.ensureBackupDir();

    try {
      // Read original file
      const content = await fs.readFile(filePath, "utf8");

      // Create backup with timestamp
      const timestamp = Date.now();
      const backupPath = this.getBackupPath(filePath, timestamp);
      await fs.writeFile(backupPath, content, "utf8");

      // Clean up old backups
      const backups = await this.getBackups(filePath);
      if (backups.length > this.maxBackups) {
        const toDelete = backups.slice(this.maxBackups);
        await Promise.all(toDelete.map((backup) => fs.unlink(backup)));
      }
    } catch (error) {
      if (error instanceof Error) {
        throw new Error(`Failed to create backup: ${error.message}`);
      }
      throw error;
    }
  }

  async getBackupInfo(
    filePath: string
  ): Promise<Array<{ path: string; timestamp: number }>> {
    const backups = await this.getBackups(filePath);
    return backups.map((backup) => ({
      path: backup,
      timestamp: parseInt(backup.split(".").slice(-2)[0]),
    }));
  }

  async rollback(filePath: string, timestamp?: number): Promise<void> {
    const backups = await this.getBackups(filePath);
    if (backups.length === 0) {
      throw new Error("No backups available for this file");
    }

    let backupToRestore: string;
    if (timestamp) {
      // Find specific backup by timestamp
      backupToRestore =
        backups.find((b) => {
          const backupTimestamp = parseInt(b.split(".").slice(-2)[0]);
          return backupTimestamp === timestamp;
        }) || backups[0];
    } else {
      // Use most recent backup
      backupToRestore = backups[0];
    }

    // Restore the backup
    const content = await fs.readFile(backupToRestore, "utf8");
    await fs.writeFile(filePath, content, "utf8");
  }
}
